# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: neo

import getpass
import html
import os
import smtplib
import socket

from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication


class _SmtpServerConfig(object):
  VALID_SENDER_DOMAIN = 'joomo.io'
  SMTP_SERVER_HOST = 'email-smtp.us-east-1.amazonaws.com'
  SMTP_SERVER_PORT = 587
  SMTP_SERVER_USER = 'AKIAII3H7NQSAWS7KWVQ'
  SMTP_SERVER_PASSWORD = 'AlQkkb+pS1IvYS3K+rt+GSJynFQF0nGziLy0uN69hEVD'


def _get_footer():
  try:
    sender_signiture = 'sent from %s@%s' % (getpass.getuser(), socket.getfqdn())
    return sender_signiture
  except Exception as e:
    logging.warning('Fail to retrieve username and fqdn.')
  return 'Unknown sender'


def _get_html_text(text, font_size=None, footer=None):
  font_size = font_size or 1.2
  html_template = '\n'.join([
      '<!DOCTYPE html>',
      '<html lang="en">',
      '  <head>',
      '    <meta charset="utf-8">',
      '  </head>',
      '  <body>',
      '    <pre style="font-size:%(font_size)gem">%(content)s</pre>',
      '    <p style="font-size:0.7em;color:#999"><i>%(footer)s</i></p>',
      '  </body>',
      '</html>'
  ])

  if not footer:
    footer = _get_footer()

  html_text = html_template % {
      'font_size': font_size, 'content': html.escape(text), 'footer': html.escape(footer)
  }
  return html_text


def _check_valid_sender(from_address, valid_sender_domain):
  splitted = from_address.split('@')
  assert len(splitted) == 2
  assert splitted[1] == valid_sender_domain


def _parse_mail_address(addrs):
  if addrs is None:
    addrs = []
  elif isinstance(addrs, str):
    addrs = [r.strip() for r in addrs.split(',')]
  return addrs


def send_raw_mail(from_addr, to_addrs, content, server_config=None):
  to_addrs = _parse_mail_address(to_addrs)
  server_config = server_config or _SmtpServerConfig

  assert isinstance(from_addr, str)
  assert isinstance(to_addrs, list)
  _check_valid_sender(from_addr, server_config.VALID_SENDER_DOMAIN)

  smtp_client = smtplib.SMTP(server_config.SMTP_SERVER_HOST, server_config.SMTP_SERVER_PORT)
  smtp_client.ehlo()
  smtp_client.starttls()
  smtp_client.ehlo()
  smtp_client.login(server_config.SMTP_SERVER_USER, server_config.SMTP_SERVER_PASSWORD)
  smtp_client.sendmail(from_addr, to_addrs, content)
  smtp_client.close()


def send_html_mail(name,
                   from_address,
                   to_address,
                   subject,
                   html_text,
                   cc_addrs=None,
                   bcc_addrs=None,
                   server_config=None):
  to_address = _parse_mail_address(to_address)
  cc_addrs = _parse_mail_address(cc_addrs)
  bcc_addrs = _parse_mail_address(bcc_addrs)

  msg = MIMEText(html_text, 'html')
  msg['From'] = '%s <%s>' % (name, from_address)
  msg['To'] = ','.join(to_address)
  if cc_addrs:
    msg['Cc'] = ','.join(cc_addrs)
  msg['Subject'] = subject

  send_raw_mail(from_address, to_address + cc_addrs + bcc_addrs, msg.as_string(), server_config)


def send_mail(name,
              from_address,
              to_address,
              subject,
              text,
              cc_addrs=None,
              bcc_addrs=None,
              server_config=None,
              font_size=None):
  html_text = _get_html_text(text, font_size=font_size)
  send_html_mail(name,
                 from_address,
                 to_address,
                 subject,
                 html_text,
                 cc_addrs,
                 bcc_addrs,
                 server_config)


def send_mail_with_attachments(name,
                               from_address,
                               to_address,
                               subject,
                               text,
                               attachment_files,
                               cc_addrs=None,
                               bcc_addrs=None,
                               server_config=None,
                               font_size=None,
                               html_text=None):
  to_address = _parse_mail_address(to_address)
  cc_addrs = _parse_mail_address(cc_addrs)
  bcc_addrs = _parse_mail_address(bcc_addrs)
  if not html_text:
    html_text = _get_html_text(text, font_size=font_size)

  msg = MIMEMultipart()
  msg['From'] = '%s <%s>' % (name, from_address)
  msg['To'] = ','.join(to_address)
  if cc_addrs:
    msg['Cc'] = ','.join(cc_addrs)
  msg['Subject'] = subject
  msg.attach(MIMEText(html_text, 'html'))

  if not isinstance(attachment_files, list):
    attachment_files = [attachment_files]

  for a_file in attachment_files:
    with open(a_file, 'rb') as fin:
      part = MIMEApplication(fin.read())
      part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(a_file))
      msg.attach(part)

  send_raw_mail(from_address, to_address + cc_addrs + bcc_addrs, msg.as_string(), server_config)


'''
# Multiple 'to_address' separated by comma.
send_mail(
    'Test Mailer',
    'test@joomo.io',
    'jaewon@prestolabs.io,neo@prestolabs.io',
    'Mail Test Multiple Address',
    'This is test mail for mail_util.py.')

# Multiple 'to_address' list
send_mail(
    'Test Mailer 2',
    'test@joomo.io',
    ['neo@prestolabs.io', 'factset.notification@prestolabs.io'],
    'Mail Test 2',
    'This is test mail for mail_util.py.')

# With CC
send_mail(
    'Test Mailer 3',
    'test@joomo.io',
    'neo@prestolabs.io',
    'Mail Test 3',
    'This is test mail for mail_util.py.',
    cc_addrs='factset.notification@prestolabs.io')

# With BCC
send_mail(
    'Test Mailer 4',
    'test@joomo.io',
    'neo@prestolabs.io',
    'Mail Test 4',
    'This is test mail for mail_util.py.',
    bcc_addrs='factset.notification@prestolabs.io')

# With attached file, and CC
send_mail_with_attachments(
    'Test Mailer 5',
    'test@joomo.io',
    'neo@prestolabs.io',
    'Mail Test 5',
    'This is test mail for mail_util.py.',
    'pylint',
    cc_addrs='factset.notification@prestolabs.io')
'''
